package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.entity.PageParam;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class DishServiceImpl  implements DishService {
    
    @Autowired
    private DishMapper mapper;
    
    @Autowired
    private DishFlavorService dishFlavorService;
    
    @Autowired
    private CategoryService categoryService;
    
    
    /**
     * 根据分类id，获取菜品数据
     *
     * @param categoryId
     * @return
     */
    @Override
    public List<DishDto> findByCategoryId(long categoryId , Integer status) {
        
        //1. 构建条件对象  select *  from dish where categoryId = ?  and status = ?
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.eq(Dish::getCategoryId , categoryId);
        qw.eq(status != null , Dish::getStatus , status);
    
        //2. 执行查询
        List<Dish> dishList = mapper.selectList(qw);
        
        //3. 由于菜品里面没有口味数据，所以要遍历他们，然后给每一个菜品都找一找它自己的口味数据，然后构建出来DishDto，装到
        // 集合里面返回
        List<DishDto> dishDtoList = dishList.stream().map(dish -> {
            
            //3.1 遍历一次，就创建一个DishDto
            DishDto  dto = new DishDto();
            
            //3.2 把dish的数据拷贝到dto身上
            BeanUtils.copyProperties(dish , dto);
            
            //3.3 设置口味数据
            dto.setFlavors(dishFlavorService.findByDishId(dish.getId()));
            
            //3.4 返回dto
            return dto;
        }).collect(Collectors.toList());
        
        return dishDtoList;
    }
    
    /**
     * 更新菜品
     *      1. 更新菜品和添加菜品一样，都要考虑操作两张表： dish &  dish_flavor
     *      2. 操作步骤：
     *          2.1 先更新菜品表
     *          2.2 再考虑更新口味表
     *              2.2.1 不能跟以前的更新一样，直接就去更新数据
     *              2.2.2 这里要考虑的点很多： 根本不知道现在口味的数据变成什么样了，是变多，还是变少了，还是根本没有变！
     *              2.2.3 可以有一个取巧的办法：
     *                  a. 先把原来这个菜品的所有口味，都删除掉
     *                  b. 再添加现在这个菜品的口味数据即可！
     *
     *
     * @param dishDto
     * @return
     */
    @Override
    public int update(DishDto dishDto) {
        //1. 更新菜品表
        int row = mapper.updateById(dishDto);
        
        //2. 更新口味表
        //2.1 删除口味数据
        dishFlavorService.delete(dishDto.getId());
        
        //2.2 执行口味的添加
        int row2 = 0 ;
        List<DishFlavor> dishFlavors = dishDto.getFlavors();
        
        if(dishFlavors != null && dishFlavors.size() >0 ){
    
            for (DishFlavor dishFlavor : dishFlavors) {
                
                //设置这种口味属于哪一种菜品
                dishFlavor.setDishId(dishDto.getId());
                
                row2 += dishFlavorService.add(dishFlavor);
            }
            return row >0 && row2 == dishFlavors.size() ? 1 :  0;
        }
    
        return row;
    }
    
    /**
     * 分页查询菜品
     *      1. 这里的分页和上一次的员工分页不一样！
     *          1.1 员工的分页，查询的是员工表，然后得到IPage<Employee> 直接返回，在整个后台代码都可以使用
     *          1.2 现在菜品分页不一样：
     *              1.2.1 前端页面必须要显示菜品的分页类名称，不显示分类的id值。
     *              1.2.2 菜品表里面保存的是分类的id值。
     *      2. 要意识到出现的问题：
     *          2.1 controller要求得到的对象是 IPage<DishDto>
     *          2.2 dao|mapper 层真的去执行分页查询得到的是： IPage<Dish>
     *          2.3 需要在service层封自己封装成IPage<DishDto>, 然后返回给上一层Controller
     *      3. 只需要记住一个核心问题，就是如果对菜品表进行分页结果的查询，得到的肯定是菜品的数据，但是唯独有一个数据
     *          不合规范（前端页面不需要），分类的id值。前端页面要的是分类的名字！
     * @param pageParam
     * @return
     */
    @Override
    public IPage<DishDto> findPage(PageParam pageParam) {
        //1. 先执行菜品表的分页查询【原来怎么写的，现在还怎么写！】
        IPage<Dish> p = new Page<>(pageParam.getPage() , pageParam.getPageSize());
        
        //1.1 设置查询条件
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.like(pageParam.getName() != null , Dish::getName , pageParam.getName());
        
        //1.2 执行查询操作
        mapper.selectPage(p , qw);
        
        //2. 自己创建IPage<DishDto> ， 向上返回。
        IPage<DishDto> dishDtoIPage = new Page<>();
        
        //2.1 页面显示数据，只需要IPage对象里面的两个属性有值即可：  records  和  total
        //2.1.1  设置total数据
        dishDtoIPage.setTotal(p.getTotal());
        
        //2.1.2  设置records数据
        //2.1.2.1 遍历原先从数据库里面查询得到的那10条记录。
        List<DishDto> list = p.getRecords().stream().map(dish ->{
            
            //a. 创建DishDto对象。遍历一次，创建一个，遍历10次，创建10个
            DishDto dishDto  = new DishDto();
            
            //b. 把Dish的数据拷贝到这个dishDto里面。
            BeanUtils.copyProperties( dish,  dishDto);
            
            //c. 基本的数据已经拷贝好了之后，还要处理分类的名称。分类的名称，可以根据菜品的分类id去查询分类表得到数据
            dishDto.setCategoryName(categoryService.findById(dish.getCategoryId()).getName());
            
            //d. 还需要给这个菜品设置口味数据，以便在页面上点击修改的时候，到了add.html 能够回显 口味的数据
            dishDto.setFlavors(dishFlavorService.findByDishId(dish.getId()));
            
            //e. 返回dishDto 即表示后面Collectors.toList()产生的集合里面的元素就是这个dishDto
            return dishDto;
        
        }).collect(Collectors.toList());
    
        //设置集合数据
        dishDtoIPage.setRecords(list);
        return dishDtoIPage;
    }
    
    /**
     * 添加菜品
     *      1. 菜品数据包含两个部分内容： a. 菜品本身的数据， b. 菜品口味数据
     *      2. 这就使得添加表的时候要添加两张表数据： 菜品表(dish) , 菜品口味表(dish_flavor)
     *      3. 操作步骤：
     *          3.1 先往菜品表里面添加它本身的基本数据
     *          3.2 再往口味表里面添加口味数据
     *              3.2.1 只有当菜品数据添加成功之后，才去做这个口味表的添加操作。
     *              3.2.2 添加口味数据之前，需要先判断当前的这个菜品是否有口味数据。
     *
     * @param dishDto
     * @return
     */
    @Override
    public int add(DishDto dishDto) {
        System.out.println("aaaaaaaaaaaaaaaaaaa");
    
        //1. 往菜品表里面添加菜品数据  DishDto  -----继承------>Dish
        int row = mapper.insert(dishDto);
        System.out.println("row = " + row);
        
        //2. 往口味表里面添加口味数据
        List<DishFlavor> flavorList = dishDto.getFlavors();
    
        //如果口味数据确实是有，那么就往口味表里面添加数据
        
        int row2 = 0 ;
        
        if(flavorList != null && flavorList.size() > 0){
            //2.1 遍历每一个口味数据
            for (DishFlavor dishFlavor : flavorList) {
                //2.2 . 给口味设置菜品的id值
                dishFlavor.setDishId(dishDto.getId());
                //2.3 添加口味数据到表里面
                row2 += dishFlavorService.add(dishFlavor);
            }
    
            //如果有口味的数据，那么判断菜品表的数据添加成功以及口味表的数据都成功，就返回1， 否则返回0
            return row >0 && row2 == flavorList.size() ? 1 :0 ;
        }
        
        // 如果没有口味数据，那么只需要返回菜品表的影响行数即可。
        return row  ;
    }
    
    /**
     * 根据分类id来查询菜品表，查询这个分类在菜品表里面的总数
     *
     * @param categoryId
     * @return
     */
    @Override
    public int findCountByCategoryId(long categoryId) {
        
        //1. 创建条件对象
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.eq(Dish::getCategoryId , categoryId);
        
        
        //执行查询  select count(*) from dish;
        //return mapper.selectCount(null);
        
        
        //执行查询  select count(*) from dish where category_id = categoryId;
        return mapper.selectCount(qw);
    }
}
